<template>
  <view class="virtual-list" style="position: relative;">
    <movable-area style="position: absolute;right: 0;width: 30px;height: 100%;">
      <movable-view class="action-bar-box" direction="vertical" :y="y" :animation="false" @change="change">
        <view style="border-bottom: #000 solid 2px;width: 100%;" />
        <view style="border-bottom: #000 solid 2px;width: 100%;" />
      </movable-view>
    </movable-area>
    <scroll-view scroll-y="true" :style="{
      height: `${scrollHeight}px`,
      position: 'relative',
      zIndex: 1,
    }" :scroll-top="scrollTop" :show-scrollbar="false" @scroll="handleScroll"
    >
      <view class="scroll-bar" :style="{
        height: `${localHeight}px`,
      }"
      />
      <view class="list" :style="{
        transform: `translateY(${offset}px)`,
      }"
      >
        <view v-for="(item, index) in visibleData" :key="index" class="item-wrap">
          <slot :item="item" :active="active"></slot>
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<script>
export default {
  name: 'MuiVirtualList',
  props: {
    // 所有的items
    items: {
      type: Array,
      default: () => []
    },
    // 可视区域的item数量
    remain: {
      type: Number,
      default: 16
    },
    // item大小
    size: {
      type: Number,
      default: 40
    },
    // 当前章节
    active: {
      type: Number,
      default: 1
    },
    // 可使区域高度
    scrollHeight: Number
  },
  data() {
    return {
      // 起始
      start: 0,
      // 结束
      end: this.remain,
      // list 偏移量
      offset: 0,
      scrollTop: 0,
      y: 0
    }
  },
  computed: {
    // 预留项
    preCount() {
      return Math.min(this.start, this.remain)
    },
    nextCount() {
      return Math.min(this.items.length - this.end, this.remain)
    },
    // 可视区域的item
    visibleData() {
      const start = this.start - this.preCount
      const end = this.end + this.nextCount
      return this.items.slice(start, end)
    },
    localHeight() {
      return this.items.length * this.size
    }
  },
  watch: {
    active(nval) {
      this.scrollTop = ''
      setTimeout(() => {
        this.scrollTop = this.size * (nval || 1)
      })
    }
  },
  created() {
    // 当前章节滚动至顶部
    this.scrollTop = this.size * this.active
  },
  methods: {
    change(e) {
      if (e.detail.source !== 'touch') {
        return
      }
      const y = e.detail.y
      let scroll = y / (this.scrollHeight - 40) * (this.localHeight - this.scrollHeight)
      scroll = scroll < 0 ? 0 : scroll
      this.scrollTop = scroll
    },
    handleScroll(ev) {
      const scrollTop = ev.detail.scrollTop
      this.y = scrollTop / (this.localHeight - this.scrollHeight) * (this.scrollHeight - 40)
      // 开始位置
      const start = Math.floor(scrollTop / this.size)
      this.start = start < 0 ? 0 : start
      // 结束位置
      this.end = this.start + this.remain
      // 计算偏移
      const offset = scrollTop - (scrollTop % this.size) - this.preCount * this.size
      this.offset = offset < 0 ? 0 : offset
    }
  }
}
</script>

<style scoped>
.list {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

.action-bar-box {
  padding: 3px;
  display: flex;
  flex-flow: column;
  justify-content: space-around;
  align-items: center;
  position: absolute;
  right: 0;
  background-color: transparent;
  border-radius: 10rpx;
  box-shadow: 0 0 5px #000;
  width: 20px;
  height: 40px;
  z-index: 2;
}
</style>
